package org.breathe.command.impl.set;

import org.breathe.command.Command;
import org.breathe.command.CommandType;
import org.breathe.datastruct.RedisBytes;
import org.breathe.datastruct.RedisData;
import org.breathe.datastruct.impl.RedisSet;
import org.breathe.protocal.Resp;
import org.breathe.protocal.decode.BulkString;
import org.breathe.protocal.decode.Errors;
import org.breathe.protocal.decode.RespArray;
import org.breathe.server.core.RedisCore;

import java.util.List;

/**
 * @author: breathe
 * @createTime: 2025-05-13
 */
public class SPop implements Command {
    private RedisCore redisCore;
    private RedisBytes key;
    private int count = 1;
    public SPop(RedisCore redisCore) {
        this.redisCore = redisCore;
    }
    @Override
    public CommandType getType() {
        return CommandType.SPOP;
    }

    @Override
    public void setContext(Resp[] array) {
        key = ((BulkString)array[1]).getContent();
        if (array.length > 2) {
            try {
                count = Integer.parseInt(((BulkString)array[2]).getContent().getString());
            } catch (Exception e) {
                count = 1;
            }
        }
    }

    @Override
    public Resp handle() {
        RedisData redisData = redisCore.get(key);
        if (redisData == null) {
            if (count == 1) {
                return new BulkString(BulkString.NULL_BYTES);
            }
            return new RespArray(new Resp[0]);
        }
        if (redisData instanceof RedisSet redisSet) {
            if (redisSet.size() == 0) {
                if (count == 1) {
                    return new BulkString(BulkString.NULL_BYTES);
                }
                return new RespArray(new Resp[0]);
            }
            List<RedisBytes> poppedElements = redisSet.pop(count);
            if (poppedElements.isEmpty()) {
                return new RespArray(new Resp[0]);
            }
            redisCore.put(key, redisSet);
            return new RespArray(poppedElements.stream().map(BulkString::new).toArray(Resp[]::new));
        }
        return new Errors("command run fail");
    }

    @Override
    public boolean writeCommand() {
        return true;
    }
}
